package com.example.server.factory;

import com.example.latch.MySqlASyncLatch;
import com.example.latch.MySqlLatchUtils;
import com.example.latch.MysqlLatchListener;
import com.example.server.po.SysServer;
import com.example.server.service.SysServerService;
import com.example.sync.service.SysASyncJobService;
import com.example.utils.TimeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author chentao
 * @version 1.0
 * @description: TODO
 * @date 2025/3/22 下午2:08
 */
@Service
public class SysServerFactory implements InitializingBean, CommandLineRunner, DisposableBean {

    Logger logger = LoggerFactory.getLogger(getClass());
    //心跳频率 默认秒
    @Value("${server.refresh.period:10}")
    private int period;

    //心跳超时的心跳间隔次数
    @Value("${server.refresh.period.size:3}")
    private int periodSize;

    //每次拉取任务数
    @Value("${sync.max.size:10}")
    private int maxSize;

    @Resource
    private DataSource dataSource;

    //运行状态
    private volatile boolean running = true;

    //是否主节点
    private volatile boolean isMaster = false;

    //启动的时间戳
    private volatile Date startTime;

    private MySqlASyncLatch mySqlASyncLatch;

    private ExecutorService executorService;

    private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;

    @Resource
    private SysASyncJobService sysASyncJobService;

    @Resource
    private SysServerService sysServerService;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.startTime = new Date();
        this.executorService = Executors.newCachedThreadPool();
        this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10);
        this.scheduledThreadPoolExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                SysServer sysServer = new SysServer();
                sysServer.setId(sysServerService.getCurrentServerId());
                sysServer.setHost(sysServerService.getHost());
                sysServer.setPort(sysServerService.getPort());
                sysServer.setJvmVersion(sysServerService.getJavaVersion());
                sysServer.setOsName(sysServerService.getOsName());
                sysServer.setOsFamily(sysServerService.getOsFamily());
                sysServer.setProcessId(sysServerService.getProcessId());
                sysServer.setMaster(isMaster);
                sysServer.setStartTime(startTime);
                sysServer.recalculateFields();
                sysServerService.saveOrUpdate(sysServer);
            }
        }, 0, period, TimeUnit.SECONDS);
    }

    @Override
    public void destroy() throws Exception {
        this.running = false;
        this.executorService.shutdownNow();
        this.scheduledThreadPoolExecutor.shutdownNow();
    }

    @Override
    public void run(String... args) throws Exception {
        MySqlLatchUtils.latchInAction(dataSource, new MysqlLatchListener() {
            @Override
            public void isLeader() {
                isMaster = true;
                while (running) {
                    List<SysServer> allServer = sysServerService.getAllServer();
                    for (SysServer sysServer : allServer) {
                        if (!TimeUtils.isLated(sysServer.getRefreshTime(), Math.negateExact(period * periodSize))) {
                            if (sysServer.getId() != (sysServerService.getCurrentServerId())) {
                                sysServerService.removeById(sysServer.getId());
                                List<SysServer> allServers = sysServerService.getAllServer();
                                for (int i = 0; i < allServers.size(); i++) {
                                    Long activeServerKey = allServers.get(i).getId();
                                    sysASyncJobService.updateASyncJobServerBatch(sysServer.getId(), activeServerKey, i, allServers.size());
                                }
                                logger.warn("server节点: " + sysServer.getId() + " 已经掉线 ...");
                            }
                        }
                    }
                    sysASyncJobService.updateASyncServer(sysServerService.getRandomServerKey(), (maxSize * 2));
                }
            }
        });
    }
}
